﻿package extremefx.ui {
	import extremefx.data.DSItem;
	import extremefx.data.DataSource;
	import extremefx.events.EventArgs;
	import extremefx.events.EventHandler;
	import extremefx.events.KeyEventArgs;
	import extremefx.events.MouseEventArgs;
	import extremefx.geom.Size;
	import extremefx.ui.styles.UIStates;
	
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;	

	/**
	 * @author Marcelo Volmaro
	 */
	public class DropDown extends UIComponent {
		private static var _lastOpened:DropDown;
		
		private var _clickOpen:Boolean;
		private var _wOpen:Boolean;
		private var _dropDownOpen:Boolean;
		
		private var _pressed:Boolean;
		private var _oldState:uint;
		private var _label:Label;
		private var _minHeight:uint;
		private var _mh:ButtonSprite;
		private var _dataSource:DataSource;
		private var _itemList:ItemList;
		private var _selItem:uint;
		private var _rectWin:Rectangle;
		private var _justOpen:Boolean;

		public function DropDown(pParameters:UIParameters = null) {
			super();

			pParameters = initStyle("DropDown", pParameters);
			pParameters._parent = this;
			_label = new Label("", pParameters);

			var vui:Sprite = _visualUI; 
			_mSprite.addChild(_label._visualUI);
			
			_label.position = new Point(_style.padding.left, _style.padding.top);
			_itemList = new ItemList();
			
			_mh = new ButtonSprite(vui);
			_mh.onRollOver.add(_rollOver);
			_mh.onRollOut.add(_rollOut);
			_mh.onReleaseOutside.add(_rollOut);
			_mh.onDragOut.add(_rollOut);
			
			_mh.onPress.add(_press);
			_mh.onDragOver.add(_press);
			
			_mh.onRelease.add(_release);
			
			//get the height from the bitmap
			_height = _minHeight = _style.getFirstBMPData().height;
			_fheight = true;
			_pressed = _clickOpen = false;
			invalidate();
		}

		public function setDataSource(pDataSource:DataSource):void{
			_dataSource = pDataSource;
			_iSetSelected(0);
		}

		private function _rollOut(pSender:ButtonSprite, pArgs:MouseEventArgs):void{
			_setView(UIStates.NORMAL);
		}

		private function _rollOver(pSender:ButtonSprite, pArgs:MouseEventArgs):void{
			_setView(UIStates.HOVER);
		}
		
		private function _press(pSender:ButtonSprite, pArgs:MouseEventArgs):void{
			_onPress();
		}

		private function _release(pSender:ButtonSprite, pArgs:MouseEventArgs):void{
			_setView(UIStates.NORMAL);
		}
		
		protected override function _keyDownHandler(pSender:KeyHandler, pArgs:KeyEventArgs):void {
			if (pArgs.keyboardEvent.keyCode == Keyboard.ESCAPE){
				if (_wOpen && _itemList._isSelected()) {
					focus();
					_changeWinState(false);
				}
			}
		}
		
		protected override function _keyUpHandler(pSender:KeyHandler, pArgs:KeyEventArgs):void {
			if (_wOpen) return;
		
			var s:uint = _selItem;
			var l:uint = _dataSource.count -1;
			
			switch (pArgs.keyboardEvent.keyCode){
				case Keyboard.UP:
					if ((--s) < 0 ) s = l;
					selectedIndex = s;
				break;
				
				case Keyboard.DOWN:
					if (pArgs.keyboardEvent.ctrlKey){
						_pressHandler();
						
					} else {
						if ((++s) > l) s = 0;
						selectedIndex = s;
					}
				break;
				
				case Keyboard.HOME:
					selectedIndex = 0;
				break;
				
				case Keyboard.END:
					selectedIndex = l;
			}
		}
		
		private function _setView(pState:uint, pForce:Boolean = false):void{
			if (_wOpen && pState != UIStates.DISABLED) pState = UIStates.ACTIVE;
			
			pState = _getState(pState);
			
			if (_oldState == pState && !pForce) return;
			_oldState = pState;
			_label.setState(pState);
			_setDecoState(pState, _width, _height);
		}
		
		private function _onPress():void {
			_changeWinState(!_wOpen);
			focus();
		}
		
		private function _changeWinState(pState:Boolean, pForce:Boolean = false):void {
			if (_wOpen == pState && !pForce) return;
			
			_wOpen = pState;
			
			if (pState){
				_setView(UIStates.ACTIVE);
				
				if (_lastOpened && _lastOpened != this){
					_lastOpened._changeWinState(false, true);
				}
				
				_lastOpened = this;
				_clickOpen = _dropDownOpen = true;
				
				var popUpWin:ItemList = _itemList = new ItemList(),
				stage:Stage = UIStage.STAGE,
				p:Point = UIStage.DROPDOWNS.globalToLocal(stage.localToGlobal(this.position));
				
				UIStage.DROPDOWNS.addChild(popUpWin._visualUI);
				popUpWin.tabEnabled(false);
				
				var ali:AbstractListItem = popUpWin.create(),
				ih:int = ali.minimumSize.height,
				visItems:uint = Math.max(Math.floor((stage.height - (p.y + _height)) / ih), Math.floor(p.y / ih));

				popUpWin.size = new Size(_width, ih);
				popUpWin.setVisibleItemCount(visItems);
				popUpWin.setDataSource(_dataSource);				
				
				_justOpen = true;
				popUpWin.onChange.add(_listSelect);
				
				UIStage.addEventListener(MouseEvent.MOUSE_UP, _releaseHandler);
				
				var up:int, puph:uint = popUpWin.size.height;
				
				if (stage.width < (p.x + _width)){
					p.x = stage.stageWidth - _width;
				}

				if (stage.stageHeight < (p.y + puph + _height)) {
					up = 0;
					p.y -= puph;
				
				} else {
					up = -_height;
					p.y += _height;
				}
				
				_rectWin = new Rectangle(p.x, p.y + up, _width, puph + _height);
			
				popUpWin.position = p;
				popUpWin.selectedIndex = _selItem;
				popUpWin.focusable(false);
				popUpWin.focus();
				
				_clickOpen = false;
				
			} else {
				UIStage.removeEventListener(MouseEvent.MOUSE_UP, _releaseHandler);
				_itemList.dispose();
				_itemList = null;
				_rectWin = null;
				_dropDownOpen = false;
				_setView(UIStates.NORMAL);
			}
		}
		
		private function _pressHandler():void{
			_changeWinState(!_wOpen);
			focus();
		}
	
		private function _releaseHandler(pE:MouseEvent):void{
			if (_rectWin.contains(UIStage.mouseX, UIStage.mouseY)) return;
			_forceClose();
		}
		
		private function _forceClose():void{
			focus();
			_changeWinState(false);
		}
		
		private function _listSelect(pSender:ItemList, pArgs:EventArgs):void{
			if (_justOpen){
				_justOpen = false;
				return;
			}

			_forceClose();
			selectedIndex = pSender.selectedIndex;
		}
		
		private function _iSetSelected(pSelected:uint):void{
			_selItem = pSelected;
			_label.text = _dataSource.getItemAt(pSelected).text;
		}
		
		public function get selectedItem():DSItem {
			return _dataSource.getItemAt(_selItem);
		}

		public function get selectedIndex():uint {
			return _selItem;
		}
		
		public function set selectedIndex(pSelected:uint):void{
			pSelected = Math.min(Math.max(pSelected, 0), _dataSource.count - 1) || 0;
			_iSetSelected(pSelected);
			if (_eOnChange) _eOnChange.fire();
		}
		
		override public function set size(pSize:Size):void {
			super.size = pSize;
			_label.size = new Size(_style.padding.getWidth(_width), _height);
		}
		
		override public function blur():void {
			if (!_clickOpen) _changeWinState(false);
			super.blur();
			_setView(UIStates.NORMAL);
		}

		override public function get preferredSize():Size {
			var lh:Size = _label.size;
			lh.width += _style.padding.left + _style.padding.right;
			lh.height = _minHeight;
			return lh;
		}
		
		override public function get minimumSize():Size {
			return preferredSize;
		}
		
		protected override function _draw():void {
			_mh.enabled = _enabled;
			
			_setView(_oldState, true);
		}

		override public function dispose():void {
			if (_disposing) return;
			
			super.dispose();
			_mh.dispose();
			
			_changeWinState(false, true);
			if (_lastOpened == this) _lastOpened = null;
			
			_label.dispose();
			_eOnChange.dispose();
		}

		private var _eOnChange:EventHandler;
		public function get onChange():EventHandler{
			if (_eOnChange == null) _eOnChange = new EventHandler(this);
			return _eOnChange;
		}
	}
}
